home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / DefaultFocusManager.java < prev    next >
Text File  |  1998-06-30  |  12KB  |  324 lines

  1. /*
  2.  * @(#)DefaultFocusManager.java    1.7 98/03/11
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing;
  21.  
  22. /**
  23.  * Default swing focus manager implementation
  24.  *
  25.  * @version 1.7 03/11/98
  26.  * @author Arnaud Weber
  27.  */
  28. import java.awt.event.KeyEvent;
  29. import java.awt.Component;
  30. import java.awt.Container;
  31. import java.awt.event.ActionEvent;
  32. import java.awt.Window;
  33. import java.awt.Dialog;
  34. import java.awt.Rectangle;
  35. import java.util.Vector;
  36.  
  37. public class DefaultFocusManager extends FocusManager {
  38.  
  39.     /** This method is called by JComponents when a key event occurs.
  40.      *  JComponent gives key events to the focus manager
  41.      *  first, then to key listeners, then to the keyboard UI dispatcher.
  42.      *  This method should look at the key event and change the focused
  43.      *  component if the key event matches the receiver's focus manager
  44.      *  hot keys. For example the default focus manager will change the
  45.      *  focus if the key event matches TAB or Shift + TAB.
  46.      *  The focus manager should call consume() on <b>anEvent</b> if 
  47.      *  <code>anEvent</code> has been processed. 
  48.      *  <code>focusedComponent</code> is the component that currently has
  49.      *  the focus.
  50.      *  Note: FocusManager will receive KEY_PRESSED, KEY_RELEASED and KEY_TYPED
  51.      *  key events. If one event is consumed, all other events type should be consumed.
  52.      */
  53.     public void processKeyEvent(Component focusedComponent,KeyEvent anEvent) {
  54.         if(anEvent.getKeyCode() == KeyEvent.VK_TAB || anEvent.getKeyChar() == '\t') {
  55.             /** If the focused component manages focus, let it do so
  56.              *  if control is not pressed 
  57.              */
  58.             if(focusedComponent instanceof JComponent) {
  59.                 JComponent fc = (JComponent) focusedComponent;
  60.                 if(fc.isManagingFocus()) {
  61.                     if(!((anEvent.getModifiers() & ActionEvent.CTRL_MASK) == 
  62.                        ActionEvent.CTRL_MASK))
  63.                         return;
  64.                 }
  65.             }
  66.  
  67.             /** If this is not a key press, consume and return **/
  68.             if(anEvent.getID() != KeyEvent.KEY_PRESSED){
  69.                 anEvent.consume();
  70.                 return;
  71.             }
  72.  
  73.             if((anEvent.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK) 
  74.                 focusPreviousComponent(focusedComponent);
  75.             else
  76.                 focusNextComponent(focusedComponent);
  77.             anEvent.consume();
  78.         }
  79.     }
  80.  
  81.     /** Cause the focus manager to set the focus on the next focusable component **/
  82.     public void focusNextComponent(Component aComponent) {
  83.         if(aComponent instanceof JComponent) {
  84.             JComponent fc  = (JComponent) aComponent;
  85.             Component nc;
  86.             Container  root = getFocusRoot(fc);
  87.             if(root != null) {
  88.                 nc = getFocusableComponentAfter(fc,root,true);
  89.                 if(nc != null) {
  90.                     if(nc instanceof JComponent)
  91.                         ((JComponent)nc).grabFocus();
  92.                     else
  93.                         nc.requestFocus();
  94.                 }
  95.             }
  96.         }
  97.     }
  98.  
  99.     /** Cause the focus manager to set the focus on the previous focusable component **/
  100.     public void focusPreviousComponent(Component aComponent) {
  101.  
  102.         if(aComponent instanceof JComponent) {
  103.             JComponent fc  = (JComponent) aComponent;
  104.             Component nc;
  105.             Container root = getFocusRoot(fc);
  106.  
  107.             if(root != null) {
  108.                 nc = getFocusableComponentAfter(fc,root,false);
  109.                 if(nc != null) {
  110.                     if(nc instanceof JComponent)
  111.                         ((JComponent)nc).grabFocus();
  112.                     else
  113.                         nc.requestFocus();
  114.                 }
  115.             }
  116.         }
  117.     }
  118.  
  119.     Container getFocusRoot(Component c) {
  120.         Container p;
  121.         for(p = c.getParent() ; p != null ; p = p.getParent()) {
  122.             if(((p instanceof JComponent) && ((JComponent)p).isFocusCycleRoot()) ||
  123.                (p instanceof Window) || (p instanceof Dialog))
  124.                 return p;
  125.         }
  126.         return null;
  127.     }
  128.  
  129.     private Component getFocusableComponentAfter(Component focusedComponent,
  130.                                                  Container rootContainer,
  131.                                                  boolean moveForward) {
  132.         Component nextComponent;
  133.         Component initialComponent;
  134.  
  135.         nextComponent = initialComponent = focusedComponent;
  136.         do {
  137.             if(moveForward)
  138.                 nextComponent = getNextComponent(nextComponent,rootContainer,true);
  139.             else
  140.                 nextComponent = getPreviousComponent(nextComponent,rootContainer);
  141.  
  142.             if(nextComponent == null)
  143.                 break;
  144.             if(nextComponent == initialComponent)
  145.                 break;
  146.         } while(!(nextComponent.isVisible() && 
  147.                   nextComponent.isFocusTraversable() && 
  148.                   nextComponent.isEnabled()));
  149.  
  150.         return nextComponent;
  151.     }
  152.  
  153.    private Component getNextComponent(Component component,
  154.                                       Container root,
  155.                                       boolean canGoDown) {
  156.        Component nsv = null;
  157.  
  158.        if(canGoDown && component.isVisible() &&
  159.           (((component instanceof JComponent)          && 
  160.             !((JComponent)component).isManagingFocus()) ||
  161.            !(component instanceof JComponent))         && 
  162.           ((component instanceof Container) && ((Container)component).getComponentCount() > 0)) {
  163.            return getFirstComponent((Container)component);
  164.        } else {
  165.            Container parent = component.getParent();
  166.            nsv = getComponentAfter(parent,component);
  167.            if(nsv != null)
  168.                return nsv;
  169.            if(parent == root)
  170.                return root;
  171.            else 
  172.                return getNextComponent(parent,root,false);
  173.        }
  174.    }
  175.  
  176.     private Component getPreviousComponent(Component component,Container root) {
  177.         Container parent = component.getParent();
  178.  
  179.         if(component == root)
  180.             return getDeepestLastComponent(root);
  181.         else {
  182.             Component nsv = getComponentBefore(parent,component);
  183.             if(nsv != null)
  184.                 return getDeepestLastComponent(nsv);
  185.             else
  186.                 return parent;
  187.         }
  188.     }
  189.  
  190.     private Component getDeepestLastComponent(Component component) {
  191.  
  192.         if(component.isVisible() &&
  193.             (((component instanceof JComponent)          && 
  194.              !((JComponent)component).isManagingFocus()) ||
  195.             !(component instanceof JComponent))         && 
  196.            ((component instanceof Container) && ((Container)component).getComponentCount() > 0)) {
  197.             return getDeepestLastComponent(getLastComponent((Container) component));
  198.         } else
  199.             return component;
  200.     }
  201.     
  202.     /** Return the first component that should receive the focus **/
  203.     public Component getFirstComponent(Container aContainer) {
  204.         Component orderedChildren[] = childrenTabOrder(aContainer);
  205.         if(orderedChildren.length > 0)
  206.             return orderedChildren[0];
  207.         else
  208.             return null;
  209.     }
  210.  
  211.     /** Return the last component that should receive the focus **/
  212.     public Component getLastComponent(Container aContainer) {
  213.         Component orderedChildren[] = childrenTabOrder(aContainer);
  214.         if(orderedChildren.length > 0)
  215.             return orderedChildren[orderedChildren.length - 1];
  216.         else
  217.             return null;
  218.     }
  219.  
  220.     /** Return the component that should receive the focus before aComponent **/
  221.     public Component getComponentBefore(Container aContainer,Component aComponent) {
  222.         Component orderedChildren[] = childrenTabOrder(aContainer);
  223.         int i,c;
  224.  
  225.         for(i=1,c=orderedChildren.length ; i < c ; i++) 
  226.             if(orderedChildren[i] == aComponent)
  227.                 return orderedChildren[i-1];
  228.         return null;
  229.     }
  230.  
  231.     /** Return the component the should receive the focus after aComponent **/
  232.     public Component getComponentAfter(Container aContainer,Component aComponent) {
  233.         Component orderedChildren[] = childrenTabOrder(aContainer);
  234.  
  235.         int i,c;
  236.         for(i=0,c=orderedChildren.length - 1; i < c ; i++) 
  237.             if(orderedChildren[i] == aComponent)
  238.                 return orderedChildren[i+1];
  239.         return null;
  240.     }
  241.  
  242.     
  243.     /** Return true if <code>a</code> should be before <code>b</code> in the
  244.      * "tab" order. Override this method if you want to change the automatic
  245.      * "tab" order. 
  246.      * The default implementation will order tab to give a left to right, top
  247.      * down order. Override this method if another order is required.
  248.      */
  249.     public boolean compareTabOrder(Component a,Component b) {
  250.         Rectangle bounds;
  251.         int ay,by;
  252.         int ax,bx;
  253.         if(a instanceof JComponent) {
  254.             ay = ((JComponent)a).getY();
  255.             ax = ((JComponent)a).getX();
  256.         } else {
  257.             bounds = a.getBounds();
  258.             ay = bounds.y;
  259.             ax = bounds.x;
  260.         }
  261.  
  262.         if(b instanceof JComponent) {
  263.             by = ((JComponent)b).getY();
  264.             bx = ((JComponent)b).getX();
  265.         } else {
  266.             bounds = b.getBounds();
  267.             by = bounds.y;
  268.             bx = bounds.x;
  269.         }
  270.  
  271.         if(Math.abs(ay - by) < 10) {
  272.             return (ax < bx);
  273.         }
  274.         return (ay < by);
  275.     }
  276.  
  277.     Component[] childrenTabOrder(Container co) {
  278.         Component children[] = co.getComponents();
  279.         Component tmp;
  280.         int i,j,c;
  281.         boolean hasLink = false;
  282.  
  283.         /** Get the tab order from the geometry **/
  284.         for(i=0,c = children.length ; i < c ; i++) {
  285.             if(!hasLink && (children[i] instanceof JComponent) &&
  286.                ((JComponent)children[i]).getNextFocusableComponent() != null)
  287.                 hasLink = true;
  288.             for(j=i ; j < c ; j++) {
  289.                 if(i==j)
  290.                     continue;
  291.                 if(compareTabOrder(children[j],children[i])) {
  292.                     tmp = children[i];
  293.                     children[i] = children[j];
  294.                     children[j] = tmp;
  295.                 }                    
  296.             }
  297.         }
  298.  
  299.         if(hasLink) {
  300.             int index;
  301.             Component nextComponent;
  302.             Vector v = new Vector(c);
  303.             for(i=0; i < c ; i++) 
  304.                 v.addElement(children[i]);
  305.  
  306.             /** Take in account the next component link **/
  307.             for(i=0 ; i < c ; i++) {
  308.                 if((children[i] instanceof JComponent) &&
  309.                    (nextComponent = ((JComponent)children[i]).getNextFocusableComponent()) != null) {
  310.                     if((index = v.indexOf(nextComponent)) != -1) {
  311.                         v.removeElementAt(index);
  312.                         v.insertElementAt(nextComponent,i+1);
  313.                     }
  314.                 }
  315.             }
  316.  
  317.             for(i=0 ; i < c ; i++) 
  318.                 children[i] = (Component) v.elementAt(i);
  319.         }
  320.  
  321.         return children;
  322.     }
  323. }
  324.